Add gradient rendering -- if the source width/height is zero, render a
authorOwen Taylor <otaylor@redhat.com>
Thu, 7 Feb 2002 05:43:55 +0000 (05:43 +0000)
committerOwen Taylor <otaylor@src.gnome.org>
Thu, 7 Feb 2002 05:43:55 +0000 (05:43 +0000)
Thu Feb  7 00:21:21 2002  Owen Taylor  <otaylor@redhat.com>

        * pixbuf-render.c (pixbuf_render): Add gradient
        rendering -- if the source width/height is zero,
        render a gradient from the surrounding values.

modules/engines/pixbuf/ChangeLog
modules/engines/pixbuf/pixbuf-render.c

index 751dfdb9a4c0e433ec4b83bf67e5f5d967359aca..a99ca73a47fc8ce6a84479efc850cd0d9a1b9581 100644 (file)
@@ -1,3 +1,9 @@
+Thu Feb  7 00:21:21 2002  Owen Taylor  <otaylor@redhat.com>
+
+       * pixbuf-render.c (pixbuf_render): Add gradient
+       rendering -- if the source width/height is zero,
+       render a gradient from the surrounding values.
+
 Mon Jan 28 15:34:43 2002  Owen Taylor  <otaylor@redhat.com>
 
        * pixbuf-render.c (compute_hint): Fix hint computation
index a0dccdf1708d62353ccf51bdf6a55116027a5f90..272613ff2d707e3fd208c226c53192680e95e32e 100644 (file)
 
 GCache *pixbuf_cache = NULL;
 
+static GdkPixbuf *
+bilinear_gradient (GdkPixbuf    *src,
+                  gint          src_x,
+                  gint          src_y,
+                  gint          width,
+                  gint          height)
+{
+  guint n_channels = gdk_pixbuf_get_n_channels (src);
+  guint src_rowstride = gdk_pixbuf_get_rowstride (src);
+  guchar *src_pixels = gdk_pixbuf_get_pixels (src);
+  guchar *p1, *p2, *p3, *p4;
+  guint dest_rowstride;
+  guchar *dest_pixels;
+  GdkPixbuf *result;
+  int i, j, k;
+
+  p1 = src_pixels + (src_y - 1) * src_rowstride + (src_x - 1) * n_channels;
+  p2 = p1 + n_channels;
+  p3 = src_pixels + src_y * src_rowstride + (src_x - 1) * n_channels;
+  p4 = p3 + n_channels;
+
+  result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
+                          width, height);
+  dest_rowstride = gdk_pixbuf_get_rowstride (result);
+  dest_pixels = gdk_pixbuf_get_pixels (result);
+
+  for (i = 0; i < height; i++)
+    {
+      guchar *p = dest_pixels + dest_rowstride *i;
+      guint v[4];
+      gint dv[4];
+
+      for (k = 0; k < n_channels; k++)
+       {
+         guint start = ((height - i) * p1[k] + (1 + i) * p3[k]) / (height + 1);
+         guint end = ((height -  i) * p2[k] + (1 + i) * p4[k]) / (height + 1);
+
+         dv[k] = (((gint)end - (gint)start) << 16) / (width + 1);
+         v[k] = (start << 16) + dv[k] + 0x8000;
+       }
+
+      for (j = width; j; j--)
+       {
+         for (k = 0; k < n_channels; k++)
+           {
+             *(p++) = v[k] >> 16;
+             v[k] += dv[k];
+           }
+       }
+    }
+
+  return result;
+}
+
+static GdkPixbuf *
+horizontal_gradient (GdkPixbuf    *src,
+                    gint          src_x,
+                    gint          src_y,
+                    gint          width,
+                    gint          height)
+{
+  guint n_channels = gdk_pixbuf_get_n_channels (src);
+  guint src_rowstride = gdk_pixbuf_get_rowstride (src);
+  guchar *src_pixels = gdk_pixbuf_get_pixels (src);
+  guint dest_rowstride;
+  guchar *dest_pixels;
+  GdkPixbuf *result;
+  int i, j, k;
+
+  result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
+                          width, height);
+  dest_rowstride = gdk_pixbuf_get_rowstride (result);
+  dest_pixels = gdk_pixbuf_get_pixels (result);
+
+  for (i = 0; i < height; i++)
+    {
+      guchar *p = dest_pixels + dest_rowstride *i;
+      guchar *p1 = src_pixels + (src_y + i) * src_rowstride + (src_x - 1) * n_channels;
+      guchar *p2 = p1 + n_channels;
+
+      guint v[4];
+      gint dv[4];
+
+      for (k = 0; k < n_channels; k++)
+       {
+         dv[k] = (((gint)p2[k] - (gint)p1[k]) << 16) / (width + 1);
+         v[k] = (p1[k] << 16) + dv[k] + 0x8000;
+       }
+      
+      for (j = width; j; j--)
+       {
+         for (k = 0; k < n_channels; k++)
+           {
+             *(p++) = v[k] >> 16;
+             v[k] += dv[k];
+           }
+       }
+    }
+
+  return result;
+}
+
+static GdkPixbuf *
+vertical_gradient (GdkPixbuf    *src,
+                  gint          src_x,
+                  gint          src_y,
+                  gint          width,
+                  gint          height)
+{
+  guint n_channels = gdk_pixbuf_get_n_channels (src);
+  guint src_rowstride = gdk_pixbuf_get_rowstride (src);
+  guchar *src_pixels = gdk_pixbuf_get_pixels (src);
+  guchar *top_pixels, *bottom_pixels;
+  guint dest_rowstride;
+  guchar *dest_pixels;
+  GdkPixbuf *result;
+  int i, j;
+
+  top_pixels = src_pixels + (src_y - 1) * src_rowstride + (src_x) * n_channels;
+  bottom_pixels = top_pixels + src_rowstride;
+
+  result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
+                          width, height);
+  dest_rowstride = gdk_pixbuf_get_rowstride (result);
+  dest_pixels = gdk_pixbuf_get_pixels (result);
+
+  for (i = 0; i < height; i++)
+    {
+      guchar *p = dest_pixels + dest_rowstride *i;
+      guchar *p1 = top_pixels;
+      guchar *p2 = bottom_pixels;
+
+      for (j = width * n_channels; j; j--)
+       *(p++) = ((height - i) * *(p1++) + (1 + i) * *(p2++)) / (height + 1);
+    }
+
+  return result;
+}
+
 static GdkPixbuf *
 replicate_single (GdkPixbuf    *src,
                  gint          src_x,
@@ -201,6 +340,27 @@ pixbuf_render (GdkPixbuf    *src,
       x_offset = src_x + rect.x - dest_x;
       y_offset = src_y + rect.y - dest_y;
     }
+  else if (src_width == 0 && src_height == 0)
+    {
+      tmp_pixbuf = bilinear_gradient (src, src_x, src_y, dest_width, dest_height);      
+      
+      x_offset = rect.x - dest_x;
+      y_offset = rect.y - dest_y;
+    }
+  else if (src_width == 0 && dest_height == src_height)
+    {
+      tmp_pixbuf = horizontal_gradient (src, src_x, src_y, dest_width, dest_height);      
+      
+      x_offset = rect.x - dest_x;
+      y_offset = rect.y - dest_y;
+    }
+  else if (src_height == 0 && dest_width == src_width)
+    {
+      tmp_pixbuf = vertical_gradient (src, src_x, src_y, dest_width, dest_height);
+      
+      x_offset = rect.x - dest_x;
+      y_offset = rect.y - dest_y;
+    }
   else if ((hints & THEME_CONSTANT_COLS) && (hints & THEME_CONSTANT_ROWS))
     {
       tmp_pixbuf = replicate_single (src, src_x, src_y, dest_width, dest_height);
@@ -388,17 +548,22 @@ theme_pixbuf_compute_hints (ThemePixbuf *theme_pb)
   gint width = gdk_pixbuf_get_width (theme_pb->pixbuf);
   gint height = gdk_pixbuf_get_height (theme_pb->pixbuf);
 
-  if (theme_pb->border_left + theme_pb->border_right >= width ||
-      theme_pb->border_top + theme_pb->border_bottom >= height)
+  if (theme_pb->border_left + theme_pb->border_right > width ||
+      theme_pb->border_top + theme_pb->border_bottom > height)
     {
       g_warning ("Invalid borders specified for theme pixmap:\n"
                 "        %s,\n"
-                "there must be at least one pixel not in the border both horizontally\n"
-                "and vertically", theme_pb->filename);
-      if (theme_pb->border_left + theme_pb->border_right >= width)
-       theme_pb->border_left = theme_pb->border_right = width / 2 + 1 - (width % 2);
-      if (theme_pb->border_bottom + theme_pb->border_top >= height)
-       theme_pb->border_bottom = theme_pb->border_top = height / 2 + 1 - (height % 2);
+                "borders don't fit within the image", theme_pb->filename);
+      if (theme_pb->border_left + theme_pb->border_right > width)
+       {
+         theme_pb->border_left = width / 2;
+         theme_pb->border_right = (width + 1) / 2;
+       }
+      if (theme_pb->border_bottom + theme_pb->border_top > height)
+       {
+         theme_pb->border_top = height / 2;
+         theme_pb->border_bottom = (height + 1) / 2;
+       }
     }
   
   for (i = 0; i < 3; i++)